package handy
{
	public class Functional
	{
		public function Functional()
		{
		}
	
		// adds methods to Object to assist functional style programming
		public static function MakeSystemFunctional():void {
			Define( "Select", function( func:Function ):Array {
				var ret:Array = new Array();
				for( var x:Object in this ) {
					var item:Object = this[x];
					if( func(item) ) {
						ret.push( item );
					}
				}
				return ret;
			});
			
			Define( "Reject", function( func:Function ):Array {
				return this.Select( function(i:*):Boolean { return !func(i) } );
			});
			
			Define( "Map", function( func:Function ):Array {
				var ret:Array = new Array();
				for( var x:Object in this ) {
					ret.push( func(this[x]) );
				}
				return ret;
			});
			
			Define( "Inject", function( acc:Object, func:Function ):Object {
				for( var x:Object in this ) {
					acc = func( acc, this[x] );
				}
				return acc;
			});
			
			Define( "All", function( func:Function=null ):Boolean {
				if(func == null) {
					func = function( i:* ):* { return i };
				}
				for ( var x:Object in this ) {
					if( !func( this[x] ) ) {
						return false;
					}
				}
				return true;
			});
			
			Define( "Any", function( func:Function=null ):Boolean {
				if(func == null) {
					func = function( i:* ):* { return i };
				}
				for ( var x:Object in this ) {
					if( func( this[x] ) ) {
						return true;
					}
				}
				return false;
			});
			
			Define( "Find", function( input:* ):Object {
				if( typeof input == "function" ) {
					var func:Function = input as Function;
					for ( var x:Object in this ) {
						if( func( this[x] ) ) {
							return this[x];
						}
					}
				} else {
					for ( var y:Object in this ) {
						if( this[y] == input ) {
							return this[y];
						}
					}
				}
				return null;
			});
			
			// TODO
			/*
				Max(func=null), Min(func=null), One(func), Drop(num), DropLast(num)
				Reverse, Sort(func)
			*/
		}
		private static function Define( Name:String, func:Function ):void {
			Object.prototype[Name] = func;
			Object.prototype.setPropertyIsEnumerable(Name, false);
		}
	}
}